// Contains code copied from istanbul-reports (https://github.com/istanbuljs/istanbuljs/tree/main/packages/istanbul-reports).
// The link to the original license is in the VENDORED.md file in the parent directory.

"use strict";
/*
 Copyright 2012-2015, Yahoo Inc.
 Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
 */
function InsertionText(text, consumeBlanks) {
  this.text = text;
  this.origLength = text.length;
  this.offsets = [];
  this.consumeBlanks = consumeBlanks;
  this.startPos = this.findFirstNonBlank();
  this.endPos = this.findLastNonBlank();
}

const WHITE_RE = /[ \f\n\r\t\v\u00A0\u2028\u2029]/;

InsertionText.prototype = {
  findFirstNonBlank() {
    let pos = -1;
    const text = this.text;
    const len = text.length;
    let i;
    for (i = 0; i < len; i += 1) {
      if (!text.charAt(i).match(WHITE_RE)) {
        pos = i;
        break;
      }
    }
    return pos;
  },
  findLastNonBlank() {
    const text = this.text;
    const len = text.length;
    let pos = text.length + 1;
    let i;
    for (i = len - 1; i >= 0; i -= 1) {
      if (!text.charAt(i).match(WHITE_RE)) {
        pos = i;
        break;
      }
    }
    return pos;
  },
  originalLength() {
    return this.origLength;
  },

  insertAt(col, str, insertBefore, consumeBlanks) {
    consumeBlanks =
      typeof consumeBlanks === "undefined" ? this.consumeBlanks : consumeBlanks;
    col = col > this.originalLength() ? this.originalLength() : col;
    col = col < 0 ? 0 : col;

    if (consumeBlanks) {
      if (col <= this.startPos) {
        col = 0;
      }
      if (col > this.endPos) {
        col = this.origLength;
      }
    }

    const len = str.length;
    const offset = this.findOffset(col, len, insertBefore);
    const realPos = col + offset;
    const text = this.text;
    this.text = text.substring(0, realPos) + str + text.substring(realPos);
    return this;
  },

  findOffset(pos, len, insertBefore) {
    const offsets = this.offsets;
    let offsetObj;
    let cumulativeOffset = 0;
    let i;

    for (i = 0; i < offsets.length; i += 1) {
      offsetObj = offsets[i];
      if (offsetObj.pos < pos || (offsetObj.pos === pos && !insertBefore)) {
        cumulativeOffset += offsetObj.len;
      }
      if (offsetObj.pos >= pos) {
        break;
      }
    }
    if (offsetObj && offsetObj.pos === pos) {
      offsetObj.len += len;
    } else {
      offsets.splice(i, 0, { pos, len });
    }
    return cumulativeOffset;
  },

  wrap(startPos, startText, endPos, endText, consumeBlanks) {
    this.insertAt(startPos, startText, true, consumeBlanks);
    this.insertAt(endPos, endText, false, consumeBlanks);
    return this;
  },

  wrapLine(startText, endText) {
    this.wrap(0, startText, this.originalLength(), endText);
  },

  toString() {
    return this.text;
  },
};

module.exports = InsertionText;
